home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1992 June: ROMin Holiday / ADC Developer CD (1992-06) (''ROMin Holiday'')_iso / Developer Connection - 06-1992.iso / Periodicals / develop / develop 7 code / Help for Print Dlogs / ModifyDialogs.c next >
Encoding:
C/C++ Source or Header  |  1991-06-24  |  22.2 KB  |  672 lines  |  [TEXT/MPS ]

  1. /* 
  2.     ModifyDialogs    -    Append items onto an existing Printing Manager dialog
  3.     
  4.     Version    When    Who            What
  5.     ------- ----    ---            ----
  6.     0.1        9/11/86 Lew            Original AppendDITL code.
  7.                     Rollins
  8.  
  9.     1.0        3/01/88    Ginger        Converted Lew's code to Pascal, and published
  10.                     Jernigan    Technical Note #95.
  11.                     
  12.     2.0        5/01/91    Zz            Fixed bug in AppendDITL - the call to PtrAndHand
  13.                                 was being passed a size that was 2 bytes too large.
  14.                                 Added Append2hdlg routine to support Help Manager
  15.                                 balloons for the items appended to the dialog.
  16.                             
  17.                                     -----
  18.     
  19.     This program is basically an updated version of the code in Technical Note #95,
  20.     "How To Add Items to the Print Dialogs".  There was a bug in the AppendDITL
  21.     routine provided in that technote that has been fixed in this code.
  22.     
  23.     The latest addition is a routine called Append2hdlg.  This routine is used
  24.     to add Help Manager 'Balloons' for the items appended onto the dialog.  As
  25.     you might have guessed, the way you add items to the hdlg resource is very
  26.     similar to the method used for DITL resources.  You basically append the
  27.     data, and then update the item count.
  28.     
  29.     This code was written under some time contraints, so it hasn't been completely
  30.     tested, but it has been tested at least once with each of the Apple printer
  31.     drivers currently available.
  32.     
  33.     It should also be noted that this code displays both the Page Setup and Print 
  34.     dialogs (unlike the original which only displayed the Print dialog), so there
  35.     are extra routines.  Basically, for every xxJobxxx routine, there is now a
  36.     xxStlxxx routine.  The routines are basically identical, the only difference
  37.     is the substitution of Stl for Job in the appropriate places.  The duplication
  38.     of code is actually meant to make things a little clearer.
  39.     
  40.     I hope this helps,
  41.     
  42.     ...Zz
  43.     
  44.     
  45.     -----------------------------------------------------------------------------
  46.     NOTE: Apple reserves the top half of the screen (where the current DITL
  47.     items are located). Applications may use the bottom half of the screen to add 
  48.     items, but should not change any items in the top half     of the screen.  An 
  49.     application should expand the print dialogs only as much as is absolutely 
  50.     necessary.
  51.     -----------------------------------------------------------------------------
  52. */
  53.  
  54. #define MPW        1
  55. #define nil 0L
  56.  
  57. #define MyDITL             256        /* resource ID of my DITL to be spliced on to job/stl dialog */
  58. #define Myhdlg             MyDITL    /* resource ID of my hdlg to be spliced on to job/stl dialog */
  59. #define    JobDlgID        -8191    /* resource ID of 'Job' or 'Print' DLOG, DITL, & hdlg         */
  60. #define    StlDlgID        -8192    /* resource ID of 'Style' or 'PageSetup' DLOG, DITL, & hdlg     */
  61. #define MyDFirstBox        1         /* Item number of first box in my DITL */
  62. #define MyDSecondBox    2
  63. #define MyDThirdBox        3
  64.  
  65. #include <Values.h>
  66. #include <Types.h>
  67. #include <Resources.h>
  68. #include <QuickDraw.h>
  69. #include <Fonts.h>
  70. #include <Events.h>
  71. #include <Windows.h>
  72. #include <Menus.h>
  73. #include <TextEdit.h>
  74. #include <Dialogs.h>
  75. #include <Desk.h>
  76. #include <ToolUtils.h>
  77. #include <Memory.h>
  78. #include <SegLoad.h>
  79. #include <Files.h>
  80. #include <OSUtils.h>
  81. #include <OSEvents.h>
  82. #include <DiskInit.h>
  83. #include <Packages.h>
  84. #include <Traps.h>
  85. #include <Printing.h>
  86.  
  87.  
  88. /* Types for accessing the Printing Manager dialog resources. */
  89. static TPPrDlg PrtJobDialog;        /* pointer to job dialog */
  90. static TPPrDlg PrtStlDialog;        /* pointer to job dialog */
  91.  
  92. struct DITLItem {            /* First, a single item */
  93.     Handle    itmHndl;        /* Handle or procedure pointer for this item */
  94.     Rect    itmRect;        /* Display rectangle for this item */
  95.     SignedByte    itmType;    /* Item type for this item — 1 byte */
  96.     SignedByte    itmData[];    /* Length byte of data */
  97. };    /*DITLItem*/
  98.  
  99. typedef    struct DITLItem        DITLItem, *pDITLItem, **hDITLItem;
  100.  
  101. struct ItemList {                /* Then, the list of items */
  102.     short        dlgMaxIndex;     /* Number of items minus 1 */
  103.     struct DITLItem    DITLItems[];     /* Array of items */
  104. };         /*ItemList*/
  105.  
  106. typedef    struct ItemList        ItemList, *pItemList, **hItemList;
  107. typedef    short    *IntPtr;
  108.  
  109. /* Types for accessing the Help Manager 'hdlg' resources. */
  110. typedef struct {
  111.     short    hdlgVers;
  112.     short    hdlg1stItem;
  113.     long    hdlgOptions;
  114.     short    hdlgProcID;
  115.     short    hdlgVarCode;
  116.     short    hdlgNumItems;
  117. } hdlgHeader, *hdlgHeaderPtr, **hdlgHeaderHdl;
  118.  
  119. typedef short *IntPtr, **IntHdl;
  120.  
  121.  
  122. /*    Declare ‘pascal’ functions and procedures */
  123. #ifndef MPW
  124. pascal Boolean PrDlgMain();        /* Print manager’s dialog handler */
  125. pascal TPPrDlg PrJobInit();        /* Gets standard print job dialog. */
  126. pascal TPPrDlg MyJobDlgInit();    /* Our extention to PrJobInit */
  127. pascal void MyJobItems();        /* Our modal item handler */
  128. pascal TPPrDlg PrStlInit();        /* Gets standard print job dialog. */
  129. pascal TPPrDlg MyStlDlgInit();    /* Our extention to PrJobInit */
  130. pascal void MyStlItems();        /* Our modal item handler */
  131. #endif
  132.  
  133.  
  134. THPrint hPrintRec;                /* handle to print record */
  135. short     FirstBoxValue = 0;        /* value of our first additional box */
  136. short     SecondBoxValue = 0;        /* value of our second addtl. box */
  137. short     ThirdBoxValue = 0;        /* value of our third addtl. box */
  138. long     prFirstItem;            /* save our first item here */
  139. ProcPtr    prPItemProc;            /* we need to store the old itemProc here */
  140.  
  141. WindowPtr     MyWindow;
  142. OSErr     err;
  143. Str255     myStr;
  144.  
  145.  
  146. /*------------------------------------------------------------------------*/
  147.  
  148. short AppendDITL(theDialog, theDITLID)
  149. DialogPtr    theDialog;
  150. short        theDITLID;
  151.  
  152. /* version 0.1 9/11/86 Lew Rollins of Human-Systems Interface Group*/
  153. /* this routine still needs some error checking */
  154.  
  155. /* This routine appends all of the items of a specified DITL
  156. onto the end of a specified DLOG — We don’t even need to know the format
  157. of the DLOG */
  158.  
  159. /* this will be done in 3 steps:
  160.  1. append the items of the specified DITL onto the existing DLOG
  161.  2. expand the original dialog window as required
  162.  3. return the adjusted number of the first new user item
  163. */
  164.  
  165. {
  166.     Point        offset;        /* Used to offset rectangles of items being appended */
  167.     Rect        maxRect;    /* Used to track increases in window size */
  168.     hItemList    hDITL;        /* Handle to DITL being appended */
  169.     pDITLItem    pItem;        /* Pointer to current item being appended */
  170.     hItemList    hItems;        /* Handle to DLOG’s item list */
  171.     short        firstItem;    /* Number of where first item is to be appended */
  172.     short        newItems,    /* Count of new items */
  173.                 dataSize,    /* Size of data for current item */
  174.                 i;             /* Working index */
  175.     union {
  176.         short        Int;
  177.         SignedByte    SBArray[2];
  178.     } USB;
  179.  
  180.  
  181.     /*
  182.      Using the original DLOG
  183.  
  184.      1. Remember the original window Size.
  185.      2. Set the offset Point to be the bottom of the original window.
  186.      3. Subtract 5 pixels from bottom and right, to be added
  187.         back later after we have possibly expanded window.
  188.      4. Get working Handle to original item list.
  189.      5. Calculate our first item number to be returned to caller.
  190.      6. Get locked Handle to DITL to be appended.
  191.      7. Calculate count of new items.
  192.     */
  193.  
  194.     maxRect = ((DialogPeek)theDialog)->window.port.portRect;
  195.     offset.v = maxRect.bottom;
  196.     offset.h = 0;
  197.     maxRect.bottom = maxRect.bottom - 5;
  198.     maxRect.right = maxRect.right - 5;
  199.  
  200.     hItems = (hItemList)(((DialogPeek)theDialog)->items);
  201.     firstItem = (*hItems)->dlgMaxIndex + 2;
  202.  
  203.     hDITL = (hItemList)GetResource('DITL', theDITLID);
  204.     HLock((Handle)hDITL);
  205.     newItems = (*hDITL)->dlgMaxIndex + 1;
  206.  
  207.     /*
  208.      For each item,
  209.       1. Offset the rectangle to follow the original window.
  210.       2. Make the original window larger if necessary.
  211.       3. fill in item Handle according to type.
  212.     */
  213.     pItem = (*hDITL)->DITLItems;
  214.     for (i = 1; i <= newItems; i++) {
  215.         OffsetRect(&pItem->itmRect, offset.h, offset.v);
  216.         UnionRect(&pItem->itmRect, &maxRect, &maxRect);
  217.  
  218.         USB.Int = 0;         /*zero things out*/
  219.         USB.SBArray[1] = pItem->itmData[0];
  220.  
  221.         /* Strip enable bit since it doesn’t matter here. */
  222.         switch (pItem->itmType & 0x7f) {
  223.             case userItem:     /* Can’t do anything meaningful with user items. */
  224.                 pItem->itmHndl = nil;
  225.                 break;
  226.                 
  227.             case (ctrlItem + btnCtrl):
  228.             case (ctrlItem + chkCtrl):
  229.             case (ctrlItem + radCtrl):                    /*build Control */
  230.                 pItem->itmHndl = (Handle)
  231.                           NewControl(theDialog,         /* theWindow */
  232.                                      &pItem->itmRect,     /* boundsRect */
  233.                                      ((StringPtr)(&pItem->itmData[0])), /* title */
  234.                                      true,                /* visible */
  235.                                      0,0,1,                /* value, min, max */
  236.                                      (pItem->itmType & 0x03), /* procID */
  237.                                      0);                 /* refCon */
  238.                 break;
  239.     
  240.             case ctrlItem + resCtrl:    /* Get resource based Control */
  241.                 pItem->itmHndl = (Handle)
  242.                           GetNewControl((*(IntPtr)&pItem->itmData[1]), /* controlID */
  243.                                         theDialog);             /* theWindow */
  244.                 (*(ControlHandle)pItem->itmHndl)->contrlRect = pItem->itmRect; /*give it the right
  245.                                                                                    rectangle*/
  246.                 /* An actionProc for a Control should be installed here */
  247.                 break;
  248.                 
  249.             case (statText):
  250.             case (editText):     /* Both need Handle to a copy of their text. */
  251.                 err = PtrToHand(&pItem->itmData[1], /* Start of data */
  252.                                 &pItem->itmHndl,     /* Address of new Handle */
  253.                                 USB.Int);             /* Length of text */
  254.                 break;
  255.  
  256.             case iconItem:         /* Icon needs resource Handle. */
  257.                 pItem->itmHndl = GetIcon(*(IntPtr)&pItem->itmData[1]);     /* ICON resID */
  258.                 break;
  259.  
  260.             case picItem:          /* Picture needs resource Handle. */
  261.                 pItem->itmHndl = (Handle)GetPicture(*(IntPtr)&pItem->itmData[1]);    /*PICT resID*/
  262.                 break;
  263.  
  264.             default:
  265.                 pItem->itmHndl = nil;
  266.                 break;
  267.  
  268.         }    /*switch*/
  269.  
  270.         dataSize = ((USB.Int + 1) & 0xfffe);
  271.  
  272.         /*now advance to next item*/
  273.         pItem = (pDITLItem)((Ptr)(pItem) + dataSize + sizeof(DITLItem));
  274.     } /*for*/
  275.  
  276.     err = PtrAndHand
  277.         ((Ptr)(*hDITL)->DITLItems, (Handle)hItems, GetHandleSize((Handle)hDITL) - 2);
  278.  
  279.     (*hItems)->dlgMaxIndex = (*hItems)->dlgMaxIndex + newItems;
  280.     HUnlock((Handle)hDITL);
  281.     ReleaseResource((Handle)hDITL);
  282.     maxRect.bottom = maxRect.bottom + 5;
  283.     maxRect.right = maxRect.right + 5;
  284.     SizeWindow(theDialog, maxRect.right, maxRect.bottom, true);
  285.     return firstItem;
  286. }    /*AppendDITL*/
  287.  
  288.  /*------------------------------------------------------------------------*/
  289.  
  290. /*--------------------------------------------------------------------------*/
  291. /*                                                                            */
  292. /* Append2hdlg - Append one 'hdlg' resource onto another.                    */
  293. /*                                                                            */
  294. /*    So what we want to do here is append the hdlg resource with resource ID    */
  295. /* srcID, onto the end of the hdlg resource, ID dstID.  Here's what these    */
  296. /* things look like:                                                        */
  297. /*                                                                            */
  298. /*                    *-----------------------------------*                    */
  299. /*                    | Header (version, options, etc.)    |                    */
  300. /*                    *-----------------------------------*                    */
  301. /*                    / # of items in item array            /                    */
  302. /*                    *-----------------------------------*                    */
  303. /*                    | Missing item marker                |                    */
  304. /*                    *-----------------------------------*                    */
  305. /*                    / Array of items                    /                    */
  306. /*                    /    …                                /                    */
  307. /*                    *-----------------------------------*                    */
  308. /*                                                                            */
  309. /* Okay, so this chart breaks up the resource into logical blocks for this    */
  310. /* excercise.  We're most interested in the blocks marked with '/'s.  The    */
  311. /* first one of these is the # of items in the item array.  We need to read    */
  312. /* this field in the source hdlg to know how many items we are adding.  We    */
  313. /* need to update this field in the destination hdlg so the Help Manager     */
  314. /* knows that we added some items.  This missing item is a generic item     */
  315. /* used by the Help Manager anytime it can't find a resource entry for an    */
  316. /* item.  In most hdlg resources, this item is simply HMSkipItem (a no op),    */
  317. /* but this code makes no assumptions about that.  It does however assume    */
  318. /* that you want to preserve the missing item in the DESTINATION hdlg,        */
  319. /* rather than copying from the source.                                      */
  320. /* So this code does this:                                                    */
  321. /*                                                                            */
  322. /*                    Source                            Destination                */
  323. /*        *---------------------------*        *---------------------------*    */
  324. /*        | Header                    |          | Header                    |    */
  325. /*        |    (version, options, etc.)|         |    (version, options, etc.)|    */
  326. /*        *---------------------------*        *---------------------------*    */
  327. /*        / # of items in item array    /--Add->/ # of items in item array    /    */
  328. /*        *---------------------------*        *---------------------------*    */
  329. /*        | Missing item                 |        | Missing item                 |    */
  330. /*        *---------------------------*        *---------------------------*    */
  331. /*                                            / Array of items            /    */
  332. /*                                            /    …                        /    */
  333. /*        *---------------------------*-Copy->*---------------------------*    */
  334. /*        / Array of items            /                                        */
  335. /*        /    …                        /                                        */
  336. /*        *---------------------------*                                        */
  337. /*                                                                            */
  338. /* Nothing to it.  The number of items is updated by adding the count from    */
  339. /* source hdlg, no 'minus 1' or anything tricky.  Then just append the item    */
  340. /* array from the source onto the end of the destination.  The Help Manager    */
  341. /* finds the new items no problem.  Okay, but since we are a guest in some-    */
  342. /* one elses closet, we need to play some games with memory.  First of all,    */
  343. /* we make sure that the destination 'hdlg' resource isn't already in mem-    */
  344. /* ory using the ol' SetResLoad trick.  If it's not there, we load it, but    */
  345. /* in any case, the hdlg is loaded into memory.  Once there, we make the    */
  346. /* rather large assumption that it's not going anywhere.  This means that    */
  347. /* we don't lock the hdlg handle, we don't even mark it non-purgeable.  The    */
  348. /* assumption is that the Help Manager will be finding the resource as soon */
  349. /* as we are done with it, and he will take care of keeping it around after    */
  350. /* that.  Once the dialog is dismissed, the resource is naturally purged,    */
  351. /* along with the changes that we made to it.  Since we never told the        */
  352. /* Resource Manager that we had changed the resource, it doesn't try to save*/
  353. /* it.                                                                        */
  354. void Append2hdlg(srcResID, dstResID)
  355. short    srcResID, dstResID;
  356. {
  357.     Handle            srcHdl, dstHdl;
  358.     Ptr                srcPtr, dstPtr;
  359.     short            srcLength, dstLength;
  360.     short            missingItmSz;
  361.     SignedByte        dstHState;
  362.     
  363.     
  364.     srcHdl = GetResource('hdlg', srcResID);    
  365.     if (srcHdl != nil) {                        
  366.         SetResLoad(false);                        /* System Resource, make sure it’s not    */
  367.         dstHdl = GetResource('hdlg', dstResID);    /* already loaded.                */
  368.         SetResLoad(true);
  369.         if (*dstHdl == 0)
  370.             dstHdl = GetResource('hdlg', dstResID);
  371.         dstHState = HGetState(dstHdl);
  372.         
  373.         if (dstHdl != nil) {
  374.             srcPtr = (Ptr)*srcHdl + sizeof(hdlgHeader);
  375.             missingItmSz = *((IntPtr)srcPtr);
  376.             srcLength = GetHandleSize(srcHdl) - (sizeof(hdlgHeader) - missingItmSz);
  377.  
  378.             dstLength = GetHandleSize(dstHdl);
  379.             SetHandleSize(dstHdl, dstLength + srcLength);
  380.             if (MemError() != noErr) {
  381.                 DebugStr("\pMemError");    /* Use this error handler, go to jail.    */
  382.                 ExitToShell();        /*        It's the law!            */
  383.             }
  384.             dstPtr = (Ptr)*dstHdl + dstLength;
  385.             srcPtr = (Ptr)*srcHdl + sizeof(hdlgHeader) + missingItmSz;
  386.  
  387.             HLock(srcHdl);
  388.             HLock(dstHdl);
  389.  
  390.             BlockMove(srcPtr, dstPtr, srcLength);
  391.  
  392.             HUnlock(srcHdl);
  393.             HSetState(dstHdl, dstHState);
  394.  
  395.             ((hdlgHeaderPtr)*dstHdl)->hdlgNumItems += ((hdlgHeaderPtr)*srcHdl)->hdlgNumItems;        
  396.             
  397.         }
  398.     }
  399.     ReleaseResource(srcHdl);
  400. }
  401.  
  402. /*-----------------------------------------------------------------------*/
  403.  
  404. /* here's the analogue to the SF dialog hook */
  405.  
  406. typedef pascal Boolean (*PrDialogProcPtr)(TPPrDlg theDialog, short itemNo);
  407.  
  408. pascal void MyJobItems(theDialog,itemNo)
  409. TPPrDlg    theDialog;
  410. short     itemNo;
  411.  
  412. { /* MyJobItems */
  413.     short     myItem;
  414.     short     firstItem;
  415.     
  416.     short    itemType;        /* needed for GetDItem/SetDItem call */
  417.     Handle    itemH;
  418.     Rect    itemBox;
  419.     
  420.     firstItem = prFirstItem; /* remember, we saved this in myJobDlgInit */
  421.     myItem = itemNo - firstItem + 1;    /* "localize" current item No */
  422.     if (myItem > 0)     /* if localized item > 0, it's one of ours */
  423.     {
  424.         /* find out which of our items was hit */
  425.         GetDItem((DialogPtr)theDialog, itemNo, &itemType, &itemH, &itemBox);
  426.         switch (myItem)
  427.         {
  428.             case MyDFirstBox:
  429.                 /* invert value of FirstBoxValue and redraw it */
  430.                 FirstBoxValue ^= 1;
  431.                 SetCtlValue((ControlHandle)itemH, FirstBoxValue);
  432.                 break;
  433.  
  434.             case MyDSecondBox:
  435.                 /* invert value of SecondBoxValue and redraw it */
  436.                 SecondBoxValue ^= 1;
  437.                 SetCtlValue((ControlHandle)itemH, SecondBoxValue);
  438.                 break;
  439.             case MyDThirdBox:
  440.                 /* invert value of SecondBoxValue and redraw it */
  441.                 ThirdBoxValue ^= 1;
  442.                 SetCtlValue((ControlHandle)itemH, ThirdBoxValue);
  443.                 break;
  444.             default: 
  445.                 Debugger(); /* OH OH */    
  446.         } /* switch */
  447.     } /* if (myItem > 0) */
  448.     else         /* chain to standard item handler, whose address is saved in prPItemProc */
  449.     {
  450.         (*((PrDialogProcPtr)prPItemProc))(theDialog,itemNo);
  451.     }
  452. } /* MyJobItems */
  453.  
  454. /*----------------------------------------------------------------------------*/
  455.  
  456. pascal TPPrDlg MyJobDlgInit(hPrint)
  457. THPrint hPrint;
  458. #pragma unused (hPrint);
  459.  
  460. /* this routine appends items to the standard job dialog and sets up the
  461.     user fields of the printing dialog record TPRDlg 
  462.     This routine will be called by PrDlgMain */
  463. {
  464.     short    firstItem;        /* first new item number */
  465.     short    itemType;        /* needed for GetDItem/SetDItem call */
  466.     Handle    itemH;
  467.     Rect    itemBox;
  468.  
  469.     /* First append onto the DITL. */
  470.     firstItem = AppendDITL(PrtJobDialog, MyDITL); /*call routine to do this */
  471.     
  472.     prFirstItem = firstItem; /* save this so MyJobItems can find it */
  473.  
  474. /* now we'll set up our DITL items -- The "First Box" */
  475.     GetDItem((DialogPtr)PrtJobDialog, firstItem, &itemType, &itemH, &itemBox);
  476.     SetCtlValue((ControlHandle)itemH, FirstBoxValue);
  477.  
  478. /* now we'll set up the second of our DITL items  -- The "Second Box" */
  479.     GetDItem((DialogPtr)PrtJobDialog, firstItem+1, &itemType, &itemH, &itemBox);
  480.     SetCtlValue((ControlHandle)itemH,SecondBoxValue);
  481.  
  482. /* Now comes the part where we patch in our item handler.  We have to save
  483.     the old item handler address, so we can call it if one of the     standard items is hit, and put our item handler's address
  484.     in pItemProc field of the TPrDlg struct
  485. */
  486.  
  487.     prPItemProc = (ProcPtr)PrtJobDialog->pItemProc;
  488.  
  489. /* Now we'll tell the modal item handler where our routine is */
  490.     PrtJobDialog->pItemProc = (PItemProcPtr)MyJobItems;
  491.  
  492. /* PrDlgMain expects a pointer to the modified dialog to be returned.... */
  493.     return PrtJobDialog;
  494.  
  495. } /*myJobDlgInit*/
  496.  
  497.  
  498. /*------------------------------------------------------------------------*/
  499.  
  500. pascal void MyStlItems(theDialog,itemNo)
  501. TPPrDlg    theDialog;
  502. short     itemNo;
  503.  
  504. { /* MyJobItems */
  505.     short     myItem;
  506.     short     firstItem;
  507.     
  508.     short    itemType;        /* needed for GetDItem/SetDItem call */
  509.     Handle    itemH;
  510.     Rect    itemBox;
  511.     
  512.     firstItem = prFirstItem; /* remember, we saved this in myJobDlgInit */
  513.     myItem = itemNo - firstItem + 1;    /* "localize" current item No */
  514.     if (myItem > 0)     /* if localized item > 0, it's one of ours */
  515.     {
  516.         /* find out which of our items was hit */
  517.         GetDItem((DialogPtr)theDialog, itemNo, &itemType, &itemH, &itemBox);
  518.         switch (myItem)
  519.         {
  520.             case MyDFirstBox:
  521.                 /* invert value of FirstBoxValue and redraw it */
  522.                 FirstBoxValue ^= 1;
  523.                 SetCtlValue((ControlHandle)itemH, FirstBoxValue);
  524.                 break;
  525.  
  526.             case MyDSecondBox:
  527.                 /* invert value of SecondBoxValue and redraw it */
  528.                 SecondBoxValue ^= 1;
  529.                 SetCtlValue((ControlHandle)itemH, SecondBoxValue);
  530.                 break;
  531.             case MyDThirdBox:
  532.                 /* invert value of SecondBoxValue and redraw it */
  533.                 ThirdBoxValue ^= 1;
  534.                 SetCtlValue((ControlHandle)itemH, ThirdBoxValue);
  535.                 break;
  536.             default: 
  537.                 Debugger(); /* OH OH */    
  538.         } /* switch */
  539.     } /* if (myItem > 0) */
  540.     else         /* chain to standard item handler, whose address is saved in prPItemProc */
  541.     {
  542.         (*((PrDialogProcPtr)prPItemProc))(theDialog,itemNo);
  543.     }
  544. } /* MyStlItems */
  545.  
  546. /*----------------------------------------------------------------------------*/
  547.  
  548. pascal TPPrDlg MyStlDlgInit(hPrint)
  549. THPrint hPrint;
  550. #pragma unused (hPrint);
  551.  
  552. /* this routine appends items to the standard job dialog and sets up the
  553.     user fields of the printing dialog record TPRDlg 
  554.     This routine will be called by PrDlgMain */
  555. {
  556.     short    firstItem;        /* first new item number */
  557.     short    itemType;        /* needed for GetDItem/SetDItem call */
  558.     Handle    itemH;
  559.     Rect    itemBox;
  560.  
  561.     /* First append onto the DITL. */
  562.     firstItem = AppendDITL(PrtStlDialog, MyDITL); /*call routine to do this */
  563.     
  564.     prFirstItem = firstItem; /* save this so MyStlItems can find it */
  565.  
  566. /* now we'll set up our DITL items -- The "First Box" */
  567.     GetDItem((DialogPtr)PrtStlDialog, firstItem, &itemType, &itemH, &itemBox);
  568.     SetCtlValue((ControlHandle)itemH, FirstBoxValue);
  569.  
  570. /* now we'll set up the second of our DITL items  -- The "Second Box" */
  571.     GetDItem((DialogPtr)PrtStlDialog, firstItem+1, &itemType, &itemH, &itemBox);
  572.     SetCtlValue((ControlHandle)itemH,SecondBoxValue);
  573.  
  574. /* Now comes the part where we patch in our item handler.  We have to save
  575.     the old item handler address, so we can call it if one of the     standard items is hit, and put our item handler's address
  576.     in pItemProc field of the TPrDlg struct
  577. */
  578.  
  579.     prPItemProc = (ProcPtr)PrtStlDialog->pItemProc;
  580.  
  581. /* Now we'll tell the modal item handler where our routine is */
  582.     PrtStlDialog->pItemProc = (PItemProcPtr)MyStlItems;
  583.  
  584. /* PrDlgMain expects a pointer to the modified dialog to be returned.... */
  585.     return PrtStlDialog;
  586.  
  587. } /*myStlDlgInit*/
  588.  
  589.  
  590. /*------------------------------------------------------------------------*/
  591.  
  592. OSErr Print()
  593. {
  594.     TPPrPort    pPrintPort;
  595.  
  596.     /* call PrJobInit to get pointer to the invisible job dialog */
  597.     hPrintRec = (THPrint)(NewHandle(sizeof(TPrint)));
  598.     if (hPrintRec) {
  599.         PrintDefault(hPrintRec);
  600.  
  601.         PrValidate(hPrintRec);
  602.         if (PrError() != noErr)
  603.             return PrError();        
  604.     
  605.         /*-------------------------------------*/
  606.  
  607.         
  608.         PrtStlDialog = PrStlInit(hPrintRec);
  609.         if (PrError() != noErr)
  610.             return PrError();        
  611.             
  612.         Append2hdlg(Myhdlg, StlDlgID);
  613.  
  614.         if (!PrDlgMain(hPrintRec, MyStlDlgInit))
  615.             return cancel;
  616.  
  617.  
  618.         /*-------------------------------------*/
  619.         
  620.         PrtJobDialog = PrJobInit(hPrintRec);
  621.         if (PrError() != noErr)
  622.             return PrError();        
  623.             
  624.         /* Next append to the hdlg resource */
  625.         Append2hdlg(Myhdlg, JobDlgID);
  626.  
  627.         if (!PrDlgMain(hPrintRec, MyJobDlgInit))    /* this line does all the stuff */
  628.             return cancel;
  629.             
  630.         /*-------------------------------------*/
  631.         
  632.         pPrintPort = PrOpenDoc(hPrintRec, nil, nil);
  633.         if (PrError() == noErr) {
  634.             PrOpenPage(pPrintPort, nil);
  635.             if (PrError() == noErr) {
  636.  
  637.                 SetPort(&pPrintPort->gPort);
  638.                 MoveTo(100, 100);
  639.                 DrawString("\pTesting...");
  640.  
  641.                 PrClosePage(pPrintPort);
  642.             } else
  643.                 return PrError();
  644.             PrCloseDoc(pPrintPort);
  645.         } else
  646.             return PrError();
  647.     }
  648. } /* Print */
  649.  
  650.  
  651. /*-----------------------------------------------------------------------*/
  652. main()
  653. {
  654. #ifdef MPW    
  655.     InitGraf(&qd.thePort);
  656. #else
  657.     InitGraf(&thePort);
  658. #endif
  659.     InitFonts();
  660.     InitWindows();
  661.     InitMenus();
  662.     InitDialogs(nil);
  663.     InitCursor();
  664.  
  665.     /* call the routine that does printing */
  666.     PrOpen();
  667.     err = Print();
  668.  
  669.     PrClose();
  670. } /* main */
  671.  
  672.